home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Pascal / Snippets / PNL Libraries / OOStaticEdit.p < prev    next >
Encoding:
Text File  |  1996-06-01  |  13.7 KB  |  508 lines  |  [TEXT/CWIE]

  1. unit OOStaticEdit;
  2.  
  3. interface
  4.  
  5.     uses
  6.         Dialogs, TextEdit;
  7.  
  8.     type
  9.         TEStaticObject = object
  10.                 window: DialogPtr;
  11.                 titem: integer;
  12.                 vcontrol, hcontrol: ControlHandle;
  13.                 te: TEHandle;
  14.                 titemr: Rect;
  15.                 hasgrow, drawgrow: boolean; { hasgrow -> leave room for grow icon, drawgrow -> draw it during updates }
  16.                 doubleClickTime, tripleClickTime: longint;
  17.                 procedure Create (dlg: DialogPtr; item, width: integer; vscroll, hscroll, hasgrowb, drawgrowb: boolean);
  18.                 procedure Destroy;
  19.                 procedure Adjust;
  20.                 procedure Resize;
  21.                 procedure Draw;
  22.                 function EditMenuEnabled: boolean;
  23.                 procedure SetEditMenuItem (item: integer);
  24.                 procedure DoEditMenu (item: integer);
  25.                 procedure DoItemWhere (er: EventRecord; item: integer);
  26.                 procedure DoIdle;
  27.                 procedure DoKey (modifiers: integer; ch: char);
  28.                 procedure DoActivateDeactivate (activate: boolean);
  29.                 procedure ClickLoop;
  30.                 procedure Click (pt: Point; extend: boolean);
  31.                 function WordBreak (text: Ptr; pos: integer; forward: boolean): boolean;
  32.             end;
  33.  
  34. implementation
  35.  
  36.     uses
  37.         Scrap, MyOOMainLoop, BaseGlobals, MyTypes, MyUtils, MySystemGlobals, MyMenus;
  38.  
  39.     var
  40.         teo: TEStaticObject;
  41.         teOriginalClickLoop: ProcPtr;
  42.  
  43. { DON'T EVEN THINK ABOUT LOOKING AT THIS CODE!!!!! }
  44.  
  45.     procedure CallCL (addr: ProcPtr);
  46.     inline
  47.         $205F, $4E90;
  48.  
  49.     procedure SetD0to1;
  50.     inline
  51.         $7001;
  52.  
  53.     function GetD2: longint;
  54.     inline
  55.         $2F42, $0000;
  56.  
  57.     procedure Unlink;
  58.     inline
  59.         $4E5E;
  60.  
  61.     procedure Link;
  62.     inline
  63.         $4E56, $0000;
  64.  
  65. {$PUSH}
  66. {$D-}
  67.   { Turn debug off, lest our qute little SetD0to1 hack gets crunged by TP }
  68.     procedure CallClickLoop;  { There must be a better way to sort out this crap! }
  69.     begin
  70.         Unlink;  { This is a rediculous hack! }
  71.         CallCL(teOriginalClickLoop);
  72.         Link;
  73.         teo.ClickLoop;
  74.         SetD0to1;
  75.     end;
  76.  
  77.     function CallWordBreak (text: Ptr; pos: integer): boolean;
  78.         var
  79.             d2: longint;
  80.     begin
  81.         d2 := GetD2;
  82.         CallWordBreak := teo.WordBreak(text, pos, BAND(d2, $00020000) = 0);
  83.     end;
  84. {$POP}
  85.  
  86.     function FindEOL (te: TEHandle; loc: integer): integer;
  87.     begin
  88.         while (loc < te^^.teLength) and (Ptr(longint(te^^.hText^) + loc)^ <> 13) do
  89.             loc := loc + 1;
  90.         FindEOL := loc;
  91.     end;
  92.  
  93.     procedure TEStaticObject.Click (pt: Point; extend: boolean);
  94.         var
  95.             tc, dct: longint;
  96.             doubleclick, tripleclick: boolean;
  97.             teOriginalWordBreak: ProcPtr;
  98.             eol: integer;
  99.     begin
  100.         SetPort(window);
  101.         tc := TickCount;
  102.         doubleclick := tc < doubleClickTime;
  103.         tripleclick := tc < tripleClickTime;
  104.         teo := self;
  105.         teOriginalClickLoop := te^^.clickLoop;
  106.         te^^.clickLoop := @CallClickLoop;
  107.         teOriginalWordBreak := te^^.wordBreak;
  108.         if tripleclick then begin
  109.             TESetWordBreak(@CallWordBreak, te);
  110.         end;
  111.         if extend and tripleclick then begin{ we must fake text edit into not shrinking the selection somehow }
  112.             eol := FindEOL(te, te^^.selStart);  { if start<=clickloc<=EOL(start)<selEnd }
  113.             if (te^^.selStart <= te^^.clickloc) and (te^^.clickloc <= eol) and (eol < te^^.selEnd) then
  114.                 TESetSelect(te^^.clickloc, te^^.selEnd, te);
  115.         end;
  116.         TEClick(pt, extend, te);
  117.         tc := TickCount;
  118.         dct := GetDblTime;
  119.         doubleClickTime := tc + dct;
  120.         if doubleclick then
  121.             tripleClickTime := tc + dct;
  122.         te^^.clickLoop := teOriginalClickLoop;
  123.         te^^.wordBreak := teOriginalWordBreak;
  124.     end;
  125.  
  126.     procedure TEStaticObject.Create (dlg: DialogPtr; item, width: integer; vscroll, hscroll, hasgrowb, drawgrowb: boolean);
  127.         var
  128.             dr, vr: Rect;
  129.             k: integer;
  130.             h: Handle;
  131.     begin
  132.         doubleClickTime := -1;
  133.         tripleClickTime := -1;
  134.         SetPort(dlg);
  135.         window := dlg;
  136.         titem := item;
  137.         hasgrow := hasgrowb;
  138.         drawgrow := drawgrowb;
  139.         if vscroll then begin
  140.             SetRect(dr, 0, 0, 16, 100);
  141.             vcontrol := NewControl(window, dr, '', true, 0, 0, 0, scrollBarProc, 0);
  142.         end
  143.         else
  144.             vcontrol := nil;
  145.         if hscroll then begin
  146.             SetRect(dr, 0, 0, 100, 16);
  147.             hcontrol := NewControl(window, dr, '', true, 0, 0, 0, scrollBarProc, 0);
  148.         end
  149.         else
  150.             hcontrol := nil;
  151.         GetDialogItem(dlg, titem, k, h, dr);
  152.         titemr := dr;
  153.         EraseRect(dr);
  154.         vr := dr;
  155.         dr.right := dr.left + width;
  156.         te := TENew(dr, vr);
  157.         TEAutoView(true, te);
  158.         Resize;
  159.     end;
  160.  
  161.     procedure TEStaticObject.Destroy;
  162.     begin
  163.         TEDispose(te);
  164.         dispose(self);
  165.     end;
  166.  
  167.     procedure AdjustTE (te: TEHandle; hc, vc: integer);
  168. {Scroll the TERec around to match up to the potentially updated scrollbar}
  169. {values. This is really useful when the window resizes such that the}
  170. {scrollbars become inactive and the TERec had been previously scrolled.}
  171.         var
  172.             value: INTEGER;
  173.     begin
  174.         with te^^ do
  175.             TEScroll((viewRect.left - destRect.left) - hc, (viewRect.top - destRect.top) - (vc * lineHeight), te);
  176.     end; {AdjustTE}
  177.  
  178.     function AdjustHV (isVert: BOOLEAN; control: ControlHandle; te: TEHandle; canRedraw: BOOLEAN): integer;
  179. {Calculate the new control maximum value and current value, whether it is the horizontal or}
  180. {vertical scrollbar. The vertical max is calculated by comparing the number of lines to the}
  181. {vertical size of the viewRect. The horizontal max is calculated by comparing the maximum document}
  182. {width to the width of the viewRect. The current values are set by comparing the offset between}
  183. {the view and destination rects. If necessary and we canRedraw, have the control be re-drawn by}
  184. {calling ShowControl.}
  185.         var
  186.             value, lines, max: INTEGER;
  187.             oldValue, oldMax: INTEGER;
  188.             cliprgn: RgnHandle;
  189.             r: Rect;
  190.     begin
  191.         oldValue := GetControlValue(control);
  192.         oldMax := GetControlMaximum(control);
  193.         with te^^ do begin
  194.             if isVert then begin
  195.                 lines := nLines;
  196.         {since nLines isn’t right if the last character is a return, check for that case}
  197.                 if (teLength > 0) & (Ptr(ORD(hText^) + teLength - 1)^ = 13) then
  198.                     lines := lines + 1;
  199.                 max := lines - ((viewRect.bottom - viewRect.top) div lineHeight);
  200.             end
  201.             else
  202.                 max := destRect.right - destRect.left - (viewRect.right - viewRect.left);
  203.             if max < 0 then
  204.                 max := 0;            {check for negative values}
  205.             if isVert then
  206.                 value := (viewRect.top - destRect.top) div lineHeight
  207.             else
  208.                 value := viewRect.left - destRect.left;
  209.             if value < 0 then
  210.                 value := 0
  211.             else if value > max then
  212.                 value := max;                    {pin the value to within range}
  213.         end;
  214.         SetPort(te^^.inPort);
  215.         clipRgn := NewRgn;
  216.         GetClip(clipRgn);
  217.         SetRect(r, 0, 0, 0, 0);
  218.         ClipRect(r);
  219.         SetControlMaximum(control, max);
  220.         SetClip(clipRgn);
  221.         DisposeRgn(clipRgn);
  222.         SetControlValue(control, value);
  223.         if canRedraw and ((max <> oldMax) or (value <> oldValue)) then
  224.             ShowControl(control);            {check to see if the control can be re-drawn}
  225.         AdjustHV := value;
  226.     end; {AdjustHV}
  227.  
  228.     procedure TEStaticObject.Adjust;
  229.         var
  230.             hc, vc: integer;
  231.     begin
  232.         vc := AdjustHV(true, vcontrol, te, false);
  233.         hc := AdjustHV(false, hcontrol, te, false);
  234.         AdjustTE(te, hc, vc);
  235.     end; {AdjustScrollValues}
  236.  
  237.     procedure TEStaticObject.Resize;
  238.         const
  239.             invis = 0;
  240.             vis = 255;
  241.             inset = 3;
  242.         var
  243.             dr, vr, r, tr: Rect;
  244.             pt: Point;
  245.             k: integer;
  246.             h: Handle;
  247.             wd, ht: integer;
  248.             hc, vc: integer;
  249.     begin
  250.         SetPort(window);
  251.         EraseRect(titemr);
  252.         GetDialogItem(window, titem, k, h, tr);
  253.         titemr := tr;
  254.         InvalRect(tr);
  255.         vr := tr;
  256.         InsetRect(vr, inset, inset);
  257.         if hcontrol <> nil then
  258.             vr.bottom := vr.bottom - 15;
  259.         if vcontrol <> nil then
  260.             vr.right := vr.right - 15;
  261.         vr.bottom := vr.top + (vr.bottom - vr.top) div te^^.lineHeight * te^^.lineHeight;
  262.  
  263.         pt := vr.topLeft;
  264.         SubPt(te^^.viewRect.topLeft, pt);
  265.         OffsetRect(te^^.destRect, pt.h, pt.v);
  266.  
  267.         te^^.viewRect := vr;
  268.  
  269.         if vcontrol <> nil then begin
  270.             vcontrol^^.contrlVis := invis;
  271.             MoveControl(vcontrol, tr.right - 16, tr.top);
  272.             ht := tr.bottom - tr.top;
  273.             if hasgrow then
  274.                 ht := ht - 15;
  275.             SizeControl(vcontrol, 16, ht);
  276.             vc := AdjustHV(true, vcontrol, te, false);
  277.             vcontrol^^.contrlVis := vis;
  278.         end;
  279.         if hcontrol <> nil then begin
  280.             hcontrol^^.contrlVis := invis;
  281.             MoveControl(hcontrol, tr.left, tr.bottom - 16);
  282.             ht := tr.right - tr.left;
  283.             if hasgrow or (vcontrol <> nil) then
  284.                 ht := ht - 15;
  285.             SizeControl(hcontrol, ht, 16);
  286.             hc := AdjustHV(false, hcontrol, te, false);
  287.             hcontrol^^.contrlVis := vis;
  288.         end;
  289.         AdjustTE(te, hc, vc);
  290.     end;
  291.  
  292.     procedure TEStaticObject.Draw;
  293.         var
  294.             r: Rect;
  295.             pt: Point;
  296.             k: integer;
  297.             h: Handle;
  298.     begin
  299.         GetDialogItem(window, titem, k, h, r);
  300.         EraseRect(r);
  301.         if drawgrow then begin
  302.             DrawGrowIcon(window);
  303.         end;
  304.         if vcontrol <> nil then begin
  305.             Draw1Control(vcontrol);
  306.         end;
  307.         if hcontrol <> nil then begin
  308.             Draw1Control(hcontrol);
  309.         end;
  310.         EraseRect(te^^.viewRect);
  311.         TEUpdate(te^^.viewRect, te);
  312.     end;
  313.  
  314.     procedure TEStaticObject.DoActivateDeactivate (activate: boolean);
  315.     begin
  316.         if drawgrow then
  317.             DrawGrowIcon(window);
  318.         if activate then
  319.             TEActivate(te)
  320.         else
  321.             TEDeactivate(te);
  322.     end;
  323.  
  324. { Common algorithm for pinning the value of a control. It returns the actual amount }
  325. { the value of the control changed. }
  326.     procedure CommonAction (control: ControlHandle; var amount: integer);
  327.         var
  328.             value, max: integer;
  329.     begin
  330.         value := GetControlValue(control);
  331.         max := GetControlMaximum(control);
  332.         amount := value - amount;
  333.         if (amount <= 0) then
  334.             amount := 0
  335.         else if (amount >= max) then
  336.             amount := max;
  337.         SetControlValue(control, amount);
  338.         amount := value - amount;   { calculate true change }
  339.     end; { CommonAction  }
  340.  
  341.     var
  342.         actionTE: TEHandle;
  343.  
  344. { Determines how much to change the value of the vertical scrollbar by and how }
  345. { much to scroll the TE record.}
  346.     procedure VActionProc (control: ControlHandle; part: integer);
  347.         var
  348.             amount: integer;
  349.             window: WindowPtr;
  350.     begin
  351.         if (part <> 0) then begin
  352.             window := control^^.contrlOwner;
  353.             case part of
  354.                 kInUpButtonControlPart, kInDownButtonControlPart:        { one line  }
  355.                     amount := 1;
  356.                 kInPageUpControlPart, kInPageDownControlPart:            { one page  }
  357.                     with actionTE^^, viewRect do
  358.                         amount := (bottom - top) div lineHeight;
  359.             end;
  360.             if ((part = kInDownButtonControlPart) or (part = kInPageDownControlPart)) then
  361.                 amount := -amount;        { reverse direction for a downer  }
  362.             CommonAction(control, amount);
  363.             if (amount <> 0) then
  364.                 TEScroll(0, amount * actionTE^^.lineHeight, actionTE);
  365.         end;
  366.     end; { VActionProc }
  367.  
  368. { Determines how much to change the value of the horizontal scrollbar by and how }
  369. { much to scroll the TE record. }
  370.     procedure HActionProc (control: ControlHandle; part: integer);
  371.         var
  372.             amount: integer;
  373.             window: WindowPtr;
  374.     begin
  375.         if (part <> 0) then begin
  376.             window := control^^.contrlOwner;
  377.             case part of
  378.                 kInUpButtonControlPart, kInDownButtonControlPart:        { a few pixels }
  379.                     amount := 8;
  380.                 kInPageUpControlPart, kInPageDownControlPart:            { a page width }
  381.                     with actionTE^^.viewRect do
  382.                         amount := (right - left);
  383.             end;
  384.             if ((part = kInDownButtonControlPart) or (part = kInPageDownControlPart)) then
  385.                 amount := -amount;        { reverse direction }
  386.             CommonAction(control, amount);
  387.             if (amount <> 0) then
  388.                 TEScroll(amount, 0, actionTE);
  389.         end;
  390.     end; { HActionProc }
  391.  
  392. { Gets called from CallClickLoop which in turn }
  393. { is called by the TEClick toolbox routine. Saves the window's clip region, }
  394. { sets it to the portRect, adjusts the scrollbar values to match the TE scroll }
  395. { amount, then restores the clip region. }
  396.     procedure TEStaticObject.ClickLoop;
  397.         var
  398.             region: RgnHandle;
  399.             vc, hc: integer;
  400.     begin
  401.         SetPort(window);
  402.         region := NewRgn;
  403.         GetClip(region);                { save the old clip }
  404.         ClipRect(window^.portRect);        { set the new clip }
  405.         vc := AdjustHV(true, vcontrol, te, false);
  406.         hc := AdjustHV(false, hcontrol, te, false);
  407.         SetClip(region);                { restore the old clip }
  408.         DisposeRgn(region);
  409.     end; { PascalClikLoop }
  410.  
  411.     function TEStaticObject.WordBreak (text: Ptr; pos: integer; forward: boolean): boolean;
  412.     begin
  413.         if forward then
  414.             WordBreak := (pos > 0) and (Ptr(longint(text) + pos - 1)^ = 13)
  415.         else
  416.             WordBreak := Ptr(longint(text) + pos)^ = 13
  417.     end;
  418.  
  419.     procedure TEStaticObject.DoItemWhere (er: EventRecord; item: integer);
  420.         var
  421.             control: ControlHandle;
  422.             value, part: integer;
  423.     begin
  424.         SetPort(window);
  425.         GlobalToLocal(er.where);
  426.         part := FindControl(er.where, window, control);
  427.         if part = 0 then begin
  428.             if PtInRect(er.where, te^^.viewRect) then
  429.                 Click(er.where, BAND(er.modifiers, shiftKey) <> 0)
  430.         end
  431.         else begin
  432.             if part = kInIndicatorControlPart then begin
  433.                 value := GetControlValue(control);
  434.                 part := TrackControl(control, er.where, nil);
  435.                 if part <> 0 then begin
  436.                     value := value - GetControlValue(control);
  437.                     if value <> 0 then
  438.                         if control = vcontrol then
  439.                             TEScroll(0, value * te^^.lineHeight, te)
  440.                         else
  441.                             TEScroll(value, 0, te);
  442.                 end;
  443.             end
  444.             else begin
  445.                 actionTE := te;
  446.                 if control = vcontrol then
  447.                     value := TrackControl(control, er.where, @VActionProc)
  448.                 else
  449.                     value := TrackControl(control, er.where, @HActionProc);
  450.             end;
  451.         end;
  452.     end;
  453.  
  454.     function TEStaticObject.EditMenuEnabled: boolean;
  455.         var
  456.             i: integer;
  457.     begin
  458.         for i := EMundo to EMselectall do
  459.             if i <> EMundo + 1 then
  460.                 SetEditMenuItem(i);
  461.         EditMenuEnabled := (te^^.selStart < te^^.selEnd) or (te^^.teLength > 0);
  462.     end;
  463.  
  464.     procedure TEStaticObject.SetEditMenuItem (item: integer);
  465.     begin
  466.         case item of
  467.             EMundo, EMcut, EMpaste, EMclear:  { Can't undo, cut, copy, paste in a static edit thingy }
  468.                 SetIDItemEnable(M_Edit, item, false);
  469.             EMcopy: 
  470.                 SetIDItemEnable(M_Edit, item, te^^.selStart < te^^.selEnd);  { Can copy iff there is a selection }
  471.             EMselectall: 
  472.                 SetIDItemEnable(M_Edit, item, te^^.teLength > 0);  { Can select all iff there is something to select }
  473.             otherwise
  474.         end;
  475.     end;
  476.  
  477.     procedure TEStaticObject.DoEditMenu (item: integer);
  478.         var
  479.             oe: OSErr;
  480.             loe: longint;
  481.     begin
  482.         case item of
  483.             EMcopy:  begin
  484.                 TECopy(te);
  485.                 loe := ZeroScrap;
  486.                 oe := TEToScrap;
  487.             end;
  488.             EMselectall:  begin
  489.                 SetPort(window);
  490.                 TESetSelect(0, maxLongInt, te);
  491.             end;
  492.             otherwise
  493.         end;
  494.     end;
  495.  
  496.     procedure TEStaticObject.DoIdle;
  497.     begin
  498.         TEIdle(te);
  499.     end;
  500.  
  501.     procedure TEStaticObject.DoKey (modifiers: integer; ch: char);
  502.     begin
  503.         if BAND(modifiers, cmdKey) = 0 then
  504.             TEKey(ch, te);
  505.         Adjust;
  506.     end;
  507.  
  508. end.